package water.com.Ioc;

import water.com.Log.Log;
import water.com.util.ConfigurationReader;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 实例构建工厂，解析注册表中的类
 * 将使用Ioc注解的类进行实例化并存入相应的Bean工厂中
 */
public class WaterBeanFactory {

    /**
     * 只用于存储通过注解化的类的实例，且只存一个
     */
    public static Map<String,Object> singleBeanFactory;

    /**
     * 存储多个注解化类的实例
     */
    public static Map<String, Queue<Object>> multipleBeanFactory;

    /**
     * 根据类名构造类实例并对其进行实例注入
     * @param beanName 类名
     * @return 实例化类对象
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static Object makeBean(String beanName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class<?> cl = Class.forName(WaterBeanRegistryInfo.registryMap.get(beanName));
        boolean hasAnnotation = cl.isAnnotationPresent(WaterBean.class);
        Object instance = null;
        if (hasAnnotation ){
            instance = cl.newInstance();
            Field[] fields = cl.getDeclaredFields();
            AccessibleObject.setAccessible(fields,true);
            for(Field field:fields){
                if(field.isAnnotationPresent(WaterInject.class)){
                    field.set(instance,makeBean(field.getType().getSimpleName()));
                }
            }
        }
       return instance;
    }

    /**
     * 初始化Bean容器，此方法在系统启动时期调用，初始化所有注解过的Bean
     * 默认单例构造，即每个实例只存在一个
     */
    public void initBeanFactory() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        singleBeanFactory = Collections.synchronizedMap(new HashMap<>());
        multipleBeanFactory = new HashMap<>();
        int size = (int) ConfigurationReader.getInstance().getValueByKey("Ioc", "serviceSize");
        for(Map.Entry<String,String> entry:WaterBeanRegistryInfo.registryMap.entrySet()){
            Class<?> cl = Class.forName(entry.getValue());
            boolean hasAnnotation = cl.isAnnotationPresent(WaterBean.class);
            if(hasAnnotation){
                WaterBean waterBean = cl.getAnnotation(WaterBean.class);
                if(waterBean.type().equals("Bean")){
                    singleBeanFactory.put(entry.getKey(),makeBean(entry.getKey()));
                }
                if(waterBean.type().equals("Service")){
                    Queue<Object> objectList = new ArrayDeque<>();
                    for(int i=0;i<size;i++){
                        objectList.add(makeBean(entry.getKey()));
                    }
                    multipleBeanFactory.put(entry.getKey(),objectList);
                }
            }
        }
        Log.getLog().info("Ioc容器初始化完毕！！");
    }

}
